/*
 * Created by Jaren at 2023/3/9 16:23
 */
import 'dart:async';
import 'dart:io';

import 'package:inmotion_protocol/common/bms_log_manager.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/lorin/protocol.dart';
import 'package:inmotion_protocol/protocol_worker.dart';
import 'package:inmotion_protocol/util/log.dart';

class LorinBmsLogManager extends AbsBmsLogManager {
  LorinBmsLogManager(super.protocol);

  @override
  _SingleBmsLogManager createSingleBmsLogManager() {
    return _SingleBmsLogManager(protocol);
  }

  @override
  List<int> bmsDevices() {
    var model = productProperty().model;
    if (model.isV13Series()) {
      return [Constant.deviceEUCV13BMS1, Constant.deviceEUCV13BMS2];
    }
    if (model.isLR1Series() || model.isRSVeloSeries()) {
      return [Constant.deviceLR1BMS];
    }
    return [];
  }
}

class _SingleBmsLogManager extends AbsSingleBmsLogManager {
  _SingleBmsLogManager(super.protocol);

  @override
  void startImpl(StreamController<UploadEvent> streamController) async {
    int total = await requestLogCount();
    LogUtils.d("BMS log count: $total");
    // 部分型号在BMS固件中，获取日志记录数量存在问题；这里默认认为最大条数1000条
    if (total > 1000) total = 1000;
    LogUtils.d("BMS log final count: $total");

    requestNext(int nextIndex, BMSLogResponse rsp) {
      streamController.add(UploadEvent(config!.device, nextIndex - 1, total));
      if (nextIndex >= total || rsp.remain == 0 || !rsp.log.isValid()) {
        // 获取结束
        streamController.add(SingleFinishedEvent(config!.device, nextIndex - 1, total, config!.output));
        streamController.close();
        return Future.value(true);
      }
      // 继续获取
      if (canceled) throw UploadError(config!.device, nextIndex - 1, UploadError.errorCanceled);
      return requestLog(nextIndex, requestNext).catchError((e) {
        streamController.addError(e);
        streamController.close();
      });
    }

    // 开始从0获取
    requestLog(0, requestNext).catchError((e) {
      streamController.addError(e);
      streamController.close();
    });
  }

  Future requestLog(int index, Function next) {
    return _protocol().requestBMSLog(config!.device, index).then((rsp) {
      LogUtils.d("request log rsp, index: ${rsp.index}, remain: ${rsp.remain}");

      // save to file
      config!.output.writeAsBytesSync(rsp.log.bytes, mode: FileMode.writeOnlyAppend, flush: true);
      return next(index + 1, rsp);
    }).catchError((e) {
      if (e is UploadError) throw e;
      throw UploadError(config!.device, index, e is MsgTimeoutException ? UploadError.errorTimeout : UploadError.errorUnknown);
    });
  }

  Future<int> requestLogCount() {
    return _protocol().requestBMSLogCount(config!.device);
  }

  LorinProtocol _protocol() {
    return protocol as LorinProtocol;
  }
}
